package cn.qicaiwang.open.qxyApi.server.Impl;


import cn.qicaiwang.open.common.enums.ResultStatusCodeEnum;
import cn.qicaiwang.open.common.response.ResponseResult;
import cn.qicaiwang.open.common.utils.StringUtils;
import cn.qicaiwang.open.qxyApi.server.QxyApiServer;
import cn.qicaiwang.open.qxyApi.server.TaxTaskResultService;
import cn.qicaiwang.open.qxyApi.util.ApiServer;
import cn.qicaiwang.open.qxyApi.util.AreaCodeUtil;
import cn.qicaiwang.open.qxyApi.util.SignUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import javafx.beans.binding.ObjectExpression;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class QxyApiServiceImpl implements QxyApiServer {

    @Autowired
    private cn.qicaiwang.open.qxyApi.config.QxyApiProperties qxyApiProperties;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private TaxTaskResultService taxTaskResultService;
    @Autowired
    private ApiServer apiServer; // 注入ApiServer



    private static final String QXY_ACCESS_TOKEN_KEY = "qxy:access_token";
    private static final long TOKEN_EXPIRE_TIME = 7 * 24 * 60 * 60; // 7天
    private static final String ETAX_COOKIE_URL = "/v2/public/login/ext/etaxcookie";//第一步   登录税局发送短信验证码（获取taskId）
    private static final String ETAX_PUSH_SMS_URL = "/v2/public/login/ext/etaxpushsms";//第二步    登录税局上传短信验证码
    private static final String ETAX_START_COLLECTION_URL   = "/v2/collect/beginFinTask";//第三步    发起企业数据采集(获取taskId)v2/collect/beginFinTask
    private static final String ETAX_GET_RESULT_URL  = "/v2/collect/getTaxAndFpInfo";//第四步    获取采集状态及全量数据
    private static final String INSIGHT_INFO_URL = "/v2/insight/info";//工商基本信息

    @Override
    public JSONObject getAccessToken() throws Exception {
        // 先从缓存获取
        JSONObject cachedToken = getAccessTokenFromCache();
        if (cachedToken != null) {
            return cachedToken;
        }

        // 缓存中没有则刷新token
        return refreshAccessToken();
    }

    @Override
    public JSONObject refreshAccessToken() {
        try {
            String appKey = qxyApiProperties.getAppKey();
            String url = qxyApiProperties.getUrl();
            String appSecret = qxyApiProperties.getAppSecret();
            String tokenUrl = url + "/v2/public/oauth2/login";
            String body = "{\"grant_type\":\"client_credentials\",\"client_appkey\":\"" + appKey + "\",\"client_secret\":\"" + md5(appSecret) + "\"}";

            HttpURLConnection conn = (HttpURLConnection) new URL(tokenUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setDoOutput(true);

            try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
                wr.write(body.getBytes(StandardCharsets.UTF_8));
            }

            String response = readResponse(conn);
            System.out.println("示例获取token结果:" + response);
            JSONObject resultJson = JSONObject.parseObject(response);
            JSONObject accessToken = resultJson.getJSONObject("data");

            // 存入Redis缓存
            redisTemplate.opsForValue().set(QXY_ACCESS_TOKEN_KEY, accessToken, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);

            return accessToken;
        } catch (Exception e) {
            // 记录错误日志，实际项目中应该使用日志框架
            System.err.println("刷新AccessToken失败: " + e.getMessage());
            throw new RuntimeException("刷新AccessToken失败", e);
        }
    }

    /**
     * {
     *   "encryptionType": 0,
     *   "nsrsbh": "91140802MA0KN46BXK",
     *   "areaCode": "1400",
     *   "gryhm": "142733198710180013",
     *   "gryhmm": "Lx520125",
     *   "sflx": "FDDBR",
     *   "sjhm": "18735994446"
     * }
     * @param requestBody
     * @return
     * @throws Exception
     */
    @Override
    public JSONObject etaxCookie(String requestBody) throws Exception {
        JSONObject jsonObject = JSONObject.parseObject(requestBody);
        String nsrsbh = jsonObject.getString("nsrsbh"); // 纳税人识别号
        JSONObject bizBasicInfo = new JSONObject();
        bizBasicInfo.put("creditNo", nsrsbh);
        JSONObject apiResult = apiServer.callApi(INSIGHT_INFO_URL, bizBasicInfo.toJSONString(), "工商基本信息");

        // 从apiResult中获取city字段
        String city = "";
        String province = "";
        String entityName = "";
        if (apiResult != null && apiResult.getBoolean("success")) {
            JSONObject data = apiResult.getJSONObject("data");
            city = data.getString("city");
            province = data.getString("province");
            entityName = data.getString("entityName");
        }

        // 获取地区代码
        String areaCode;
        if (!city.isEmpty()) {
            // 首先尝试用城市获取代码
            areaCode = AreaCodeUtil.getAreaCode(city);

            // 如果城市代码是0000，则回退使用省份
            if ("0000".equals(areaCode)) {
                areaCode = AreaCodeUtil.getAreaCode(province);
            }
        } else {
            // 如果没有city信息，直接使用省份
            areaCode = AreaCodeUtil.getAreaCode(province);
        }

        JSONObject etaxcookie = new JSONObject();
        etaxcookie.put("nsrsbh", nsrsbh);
        etaxcookie.put("areaCode", areaCode);
        etaxcookie.put("gryhm", jsonObject.getString("gryhm"));
        etaxcookie.put("gryhmm", jsonObject.getString("gryhmm"));
        etaxcookie.put("sflx", "FDDBR");
        etaxcookie.put("sjhm", jsonObject.getString("gryhm"));

        JSONObject etaxcookieapiResult = apiServer.callApi(ETAX_COOKIE_URL, etaxcookie.toJSONString(), "登录税局发送短信验证码（获取taskId）");

        // 提取taskId并转换为字符串
        String taskId = "";
        if (etaxcookieapiResult != null && etaxcookieapiResult.getBoolean("success")) {
            JSONObject data = etaxcookieapiResult.getJSONObject("data");
            taskId = String.valueOf(data.getLong("taskId")); // 确保taskId以字符串形式返回
        }

        // 将taskId添加到返回结果中
        jsonObject.put("taskId", taskId);

        return jsonObject;
    }



    public JSONObject getAccessTokenFromCache() {
        try {
            return (JSONObject) redisTemplate.opsForValue().get(QXY_ACCESS_TOKEN_KEY);
        } catch (Exception e) {
            System.err.println("从缓存获取AccessToken失败: " + e.getMessage());
            return null;
        }
    }

    private static String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private static String base64Encode(String input) {
        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
        return Base64.getEncoder().encodeToString(inputBytes);
    }






    @Override
    public JSONObject insight(String requestBody) throws Exception {
        // 1. 获取access_token
        JSONObject tokenInfo = getAccessToken();
        String accessToken = tokenInfo.getString("access_token");

        // 2. 构建完整URL
        String apiUrl = qxyApiProperties.getUrl() + INSIGHT_INFO_URL;

        // 3. 生成请求时间戳
        String reqDate = String.valueOf(System.currentTimeMillis());

        // 4. 使用传入的请求体，确保签名和实际发送内容一致
        JSONObject requestJson = JSONObject.parseObject(requestBody);
        String requestBodyStr = requestJson.toJSONString();

        // 5. 生成签名
        String reqSign = SignUtil.generateSign(
                qxyApiProperties.getAppKey(),
                qxyApiProperties.getAppSecret(),
                accessToken,
                reqDate,
                requestBodyStr
        );

        // 6. 准备请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("access_token", accessToken);
        headers.put("req_date", reqDate);
        headers.put("req_sign", reqSign);
        headers.put("Content-Type", "application/json;charset=UTF-8");

        // 7. 调用第三方API
        String response = sendPostRequest(apiUrl, headers, requestBodyStr);

        // 8. 解析响应 - 这里需要根据实际返回结构修改
        JSONObject responseJson = JSONObject.parseObject(response);
        // TODO: 实现实际解析逻辑
        return responseJson;
    }

    @Override
    public JSONObject etaxpushsms(String requestBody) throws Exception {
        // 1. 获取access_token
        JSONObject tokenInfo = getAccessToken();
        String accessToken = tokenInfo.getString("access_token");

        // 2. 构建完整URL
        String apiUrl = qxyApiProperties.getUrl() + ETAX_PUSH_SMS_URL;

        // 3. 生成请求时间戳
        String reqDate = String.valueOf(System.currentTimeMillis());

        // 4. 使用传入的请求体，确保签名和实际发送内容一致
        JSONObject requestJson = JSONObject.parseObject(requestBody);
        String requestBodyStr = requestJson.toJSONString();

        // 5. 生成签名
        String reqSign = SignUtil.generateSign(
                qxyApiProperties.getAppKey(),
                qxyApiProperties.getAppSecret(),
                accessToken,
                reqDate,
                requestBodyStr
        );

        // 6. 准备请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("access_token", accessToken);
        headers.put("req_date", reqDate);
        headers.put("req_sign", reqSign);
        headers.put("Content-Type", "application/json;charset=UTF-8");

        // 7. 调用第三方API
        String response = sendPostRequest(apiUrl, headers, requestBodyStr);

        // 8. 解析响应 - 这里需要根据实际返回结构修改
        JSONObject responseJson = JSONObject.parseObject(response);

        return responseJson;
    }

    @Override
    public ResponseResult pushSmsAndBeginTask(String requestBody) throws Exception {
        ResponseResult result=
                new ResponseResult(ResultStatusCodeEnum.HTTP_ERROR.getCode(),ResultStatusCodeEnum.HTTP_ERROR.getDesc());

        //JSONObject requestJson = JSONObject.parseObject(requestBody);
        Object smsCode=JSONPath.read(requestBody,"$.smsCode");
        Object taskId=JSONPath.read(requestBody,"$.taskId");
        if(StringUtils.isEmpty(taskId==null?null:taskId.toString())&&StringUtils.isEmpty(smsCode==null?null:smsCode.toString())){
            log.info("已授权 无需验证码发起企业数据采集");
            if(beginFinTask(requestBody)){
                log.info("企业数据采集完成");
                result.setCode(ResultStatusCodeEnum.HTTP_SUCCESS.getCode());
                result.setMsg(ResultStatusCodeEnum.HTTP_SUCCESS.getDesc());
            }
        }else{
            //上传短信验证码
            JSONObject responseJson = etaxpushsms(requestBody);
            String smsFlag= JSONPath.read(responseJson.toJSONString(),"$.code").toString();

            if("2000".equals(smsFlag)){
                log.info("上传短信验证码成功 发起企业数据采集");
                //发起企业数据采集
                if(beginFinTask(requestBody)){
                    log.info("企业数据采集完成");
                    result.setCode(ResultStatusCodeEnum.HTTP_SUCCESS.getCode());
                    result.setMsg(ResultStatusCodeEnum.HTTP_SUCCESS.getDesc());
                }
            }else{
                log.info("上传短信验证码失败");
                result.setMsg("上传短信验证码失败");
            }
        }




        return result;
    }

    @Override
    public Boolean beginFinTask(String requestBody) throws Exception {
        // 1. 获取access_token
        JSONObject tokenInfo = getAccessToken();
        String accessToken = tokenInfo.getString("access_token");

        // 2. 构建完整URL
        String apiUrl = qxyApiProperties.getUrl() + ETAX_START_COLLECTION_URL;

        // 3. 生成请求时间戳
        String reqDate = String.valueOf(System.currentTimeMillis());

        // 4. 使用传入的请求体，确保签名和实际发送内容一致
        JSONObject requestJson = JSONObject.parseObject(requestBody);
        String nsrsbh=requestJson.getString("nsrsbh");
        String userId=requestJson.getString("userId");
        JSONObject bizBasicInfo = new JSONObject();
        bizBasicInfo.put("creditNo", nsrsbh);
        JSONObject apiResult = apiServer.callApi(INSIGHT_INFO_URL, bizBasicInfo.toJSONString(),"工商基本信息");
        // 从apiResult中获取city字段
        String city = "";
        String province = "";
        String entityName = "";
        if (apiResult != null && apiResult.getBoolean("success")) {
            JSONObject data = apiResult.getJSONObject("data");
            city = data.getString("city");
            province = data.getString("province");
            entityName = data.getString("entityName");
        }

        // 获取地区代码
        String areaCode;
        if (!city.isEmpty()) {
            // 首先尝试用城市获取代码
            areaCode = AreaCodeUtil.getAreaCode(city);

            // 如果城市代码是0000，则回退使用省份
            if ("0000".equals(areaCode)) {
                areaCode = AreaCodeUtil.getAreaCode(province);

            }
        } else {
            // 如果没有city信息，直接使用省份
              areaCode = AreaCodeUtil.getAreaCode(province);
        }
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        // 设置采集日期起(cjyfq)为当前年月，格式为yyyyMM
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
        String cjyfz = currentDate.format(formatter);

        // 设置采集日期停(cjyfz)为当前年份的前3年的第一个月，格式为yyyyMM
        LocalDate threeYearsAgo = currentDate.minusYears(3).withMonth(1).withDayOfMonth(1); // 关键修改点
        String cjyfq = threeYearsAgo.format(formatter);
        requestJson.put("cjyfq", cjyfq); // 采集日期起
        requestJson.put("cjyfz", cjyfz); // 采集日期停
        requestJson.put("updateCache", "1");//缓存
        requestJson.put("nsrsbh", nsrsbh);//纳税人识别号
        requestJson.put("areaCode", areaCode);//区域代码
        requestJson.remove("userId");

        String requestBodyStr = requestJson.toJSONString();

        // 5. 生成签名
        String reqSign = SignUtil.generateSign(
                qxyApiProperties.getAppKey(),
                qxyApiProperties.getAppSecret(),
                accessToken,
                reqDate,
                requestBodyStr
        );

        // 6. 准备请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("access_token", accessToken);
        headers.put("req_date", reqDate);
        headers.put("req_sign", reqSign);
        headers.put("Content-Type", "application/json;charset=UTF-8");

        // 7. 调用第三方API
        String response = sendPostRequest(apiUrl, headers, requestBodyStr);

        // 8. 解析响应 - 这里需要根据实际返回结构修改
        JSONObject responseJson = JSONObject.parseObject(response);

        String beginFinTaskcode = responseJson.getString("code");
        if ("2000".equals(beginFinTaskcode)) {
            // 获取 data 对象
            JSONObject data = responseJson.getJSONObject("data");

            // 从 data 对象中获取 taskId
            String taskId = data.getString("taskId");

            // 创建 taxAndFpInfo 对象并设置字段
            JSONObject taxAndFpInfo = new JSONObject();
            taxAndFpInfo.put("nsrsbh", nsrsbh);
            taxAndFpInfo.put("taskId", taskId);
            taxAndFpInfo.put("userId", userId);
            taxAndFpInfo.put("entityName", entityName);
            String taxAndFpInfoRequestBodyStr = taxAndFpInfo.toJSONString();
            Boolean taxAndFpInfo1 = getTaxAndFpInfo(taxAndFpInfoRequestBodyStr);
            return taxAndFpInfo1;
            // 后续处理...
        } else {
            return false;
        }


    }

    @Override
    public Boolean getTaxAndFpInfo(String requestBody) throws Exception {
        // 固定1秒1次轮询（无次数限制）
        final long FIXED_INTERVAL = 1000; // 固定间隔1秒（毫秒）

        // 初始化统计变量
        int requestCount = 0;
        long startTime = System.currentTimeMillis();

        // 初始化请求参数
        JSONObject tokenInfo = getAccessToken();
        String accessToken = tokenInfo.getString("access_token");
        String apiUrl = qxyApiProperties.getUrl() + ETAX_GET_RESULT_URL;
        JSONObject requestJson = JSONObject.parseObject(requestBody);
        String taskId = requestJson.getString("taskId");
        String nsrsbh = requestJson.getString("nsrsbh");
        String userId = requestJson.getString("userId");
        String entityName = requestJson.getString("entityName");
        // 创建不包含userId和entityName的请求体
        JSONObject requestBodyWithoutSensitive = new JSONObject();
        requestBodyWithoutSensitive.put("taskId", taskId);
        requestBodyWithoutSensitive.put("nsrsbh", nsrsbh);
        // 不包含userId和entityName
        String requestBodyStr = requestBodyWithoutSensitive.toJSONString();
        while (true) {
            requestCount++; // 请求计数器+1

            // 打印当前统计信息（每次请求前）
            long elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000;
            System.out.printf("[第%d次请求] 已执行: %d秒 %n", requestCount, elapsedSeconds);

            // 1. 生成动态签名和时间戳
            String reqDate = String.valueOf(System.currentTimeMillis());
            String reqSign = SignUtil.generateSign(
                    qxyApiProperties.getAppKey(),
                    qxyApiProperties.getAppSecret(),
                    accessToken,
                    reqDate,
                    requestBodyStr
            );

            // 2. 设置请求头
            Map<String, String> headers = new HashMap<>();
            headers.put("access_token", accessToken);
            headers.put("req_date", reqDate);
            headers.put("req_sign", reqSign);
            headers.put("Content-Type", "application/json;charset=UTF-8");

            // 3. 发送请求
            String response = sendPostRequest(apiUrl, headers, requestBodyStr);
            JSONObject responseJson = JSONObject.parseObject(response);
            System.out.println(responseJson);

            // 4. 安全解析状态（改进后的代码）
            String mainStatus = null;
            String mainStatusCode = null;

            try {
                JSONObject data = responseJson.getJSONObject("data");
                if (data != null) {
                    JSONObject statusDetails = data.getJSONObject("statusDetails");
                    if (statusDetails != null) {
                        mainStatus = statusDetails.getString("main");
                        mainStatusCode = statusDetails.getString("mainStatusCode");
                    }
                }
            } catch (Exception e) {
                System.err.println("解析响应状态时出错: " + e.getMessage());
                // 可以继续下一次轮询
                continue;
            }

            // 5. 状态判断（增加null检查）
            if (mainStatus == null || mainStatusCode == null) {
                System.out.println("⚠️ 未获取到有效状态信息，继续轮询...");
                continue;
            }

            if ("3".equals(mainStatus) && "2000".equals(mainStatusCode)) {
                long totalSeconds = (System.currentTimeMillis() - startTime) / 1000;
                long totalTime = System.currentTimeMillis() - startTime;
                System.out.printf("✅ 任务成功! 总请求次数: %d次, 总耗时: %d秒 %n",
                        requestCount, totalSeconds);
                System.out.println("执行入库操作...");
                // 构建入库对象
                // 保存结果
                taxTaskResultService.saveOrUpdateTaskResult(
                        nsrsbh, taskId, requestCount, totalTime,
                        responseJson, mainStatus, mainStatusCode,userId,entityName
                );
                //通过userId查询 报告查询次数
                Integer reportCount = taxTaskResultService.getReportCount(userId);
                int updatedCount = reportCount - 1;
                // 更新减1后的次数回数据库
                taxTaskResultService.updateReportCount(userId, updatedCount);

                return true;

            }
            else if ("2".equals(mainStatus)) {
                long totalSeconds = (System.currentTimeMillis() - startTime) / 1000;
                System.out.printf("❌ 任务失败! 总请求次数: %d次, 总耗时: %d秒, 错误码: %s %n",
                        requestCount, totalSeconds, mainStatusCode);
                throw new Exception("任务失败: " + mainStatusCode);
            }

            // 6. 固定等待1秒
            long startWait = System.currentTimeMillis();
            while (System.currentTimeMillis() - startWait < FIXED_INTERVAL) {
                Thread.sleep(50);
            }
        }
    }

    @Override
    public Integer getReportCount(String userId) {
        Integer i= taxTaskResultService.getReportCount(userId);
        return i;
    }

    private String sendPostRequest(String url, Map<String, String> headers, String body) throws Exception {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");

        // 设置请求头
        headers.forEach(conn::setRequestProperty);

        conn.setDoOutput(true);
        try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
            wr.write(body.getBytes(StandardCharsets.UTF_8));
        }

        return readResponse(conn);
    }



    // 保留原有的readResponse方法
    private static String readResponse(HttpURLConnection conn) throws IOException {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
            String inputLine;
            StringBuilder content = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            return content.toString();
        }
    }
}
